#include "twophaselock.h"

char *cmd1="ACQLOCK Flist";
char *cmd2="RELLOCK Flist";
int send_1_command(char *serv_addr, int port, char* cmd_in);

void * server_network_func(void *arg)
{
	int fd, cli_s;
	int flag=0; 
	struct sockaddr_in addr;
	char *data_in, *data_out;
	int count;
	char cmd_type[10];
	int optval=1;
	
	char *myaddr=malloc(DATA_SIZE);
	memset(myaddr, 0, DATA_SIZE);
	myaddr = (char*)arg;
		
	fd = socket(PF_INET,  SOCK_STREAM, 0);
	if(fd <0)
	{	
		perror("error to creat socket!\n");
		pthread_exit(0);
	}

	setsockopt(fd,SOL_SOCKET,SO_REUSEADDR, &optval, sizeof(optval));
	addr.sin_family = PF_INET;
	addr.sin_port = PORT;
	inet_aton(myaddr, &addr.sin_addr);

	if(bind(fd, (struct sockaddr*)&addr, sizeof(struct sockaddr_in))<0)
	{
		perror("bind error\n");
		goto out;
	}

  	if (listen(fd, 5) == -1) 
	{
   		perror("Error in listen call");
   	 	goto out;
 	 }
  
	for(;;)
	{
		if((cli_s = accept(fd, NULL, NULL))<0)
		{
			perror("accept error\n");
			break;
		}

 		if (!(data_in = (char*)malloc(DATA_SIZE))) 
	 	{
  			fprintf(stderr, "Unable to allocate memory.\n\n");
			close(cli_s); 
 			break;
	 	}

		count = read(cli_s, data_in, DATA_SIZE);

		sscanf(data_in, "%s", cmd_type);
		cmd_type[strlen(cmd_type)+1]='\0';
		
		if(!(data_out = (char*)malloc(DATA_SIZE)))
		{
			fprintf(stderr, "Unable to allocate memory.\n\n");
  			close(cli_s);
			break;
		}
		
		DEBUG("cmd: %s\n", cmd_type);
		if(strcmp(cmd_type, ACQLOCK)==0)
		{
			DEBUG("GET LOCK!\n");
			
			if(flag==0)
			{
				flag = 1;
				strcpy(data_out, "OK");
			}
			else strcpy(data_out,"ERR");	
		}
		if(strcmp(cmd_type, RELLOCK)==0)
		{
			DEBUG("RELEASE LOCK!\n");
			flag = 0;
			strcpy(data_out, "OK");
		}

		DEBUG("data_out: %s\n", data_out);
		printf("flag is: %d\n", flag);
		write(cli_s, data_out, DATA_SIZE);
		free(data_out);
		free(data_in);
		close(cli_s);
	}

	
out:
	 close(fd);
	 pthread_exit(0);
}

int init_client_network(void *arg)
{
	int fd;
	struct sockaddr_in addr;
	int optval=1;
	
	char *myaddr=malloc(DATA_SIZE);
	memset(myaddr, 0, DATA_SIZE);
	myaddr = (char*)arg;
		
	fd = socket(PF_INET,  SOCK_STREAM, 0);
	if(fd <0)
	{	
		perror("error to creat socket!\n");
		free(myaddr);
		return -1;
	}

	setsockopt(fd,SOL_SOCKET,SO_REUSEADDR, &optval, sizeof(optval));
	addr.sin_family = PF_INET;
	addr.sin_port = C_PORT;
	inet_aton(myaddr, &addr.sin_addr);

	if(bind(fd, (struct sockaddr*)&addr, sizeof(struct sockaddr_in))<0)
	{
		perror("bind error\n");
	        close(fd);
	        free(myaddr);
		return -1;
	}

  	if (listen(fd, 5) == -1) 
	{
   		perror("Error in listen call");
   	 	close(fd);
		free(myaddr);
		return -1;
 	 }
	
	return fd;
} 
	


int main (int argc, char* argv[])
{
	pthread_t tid;
	int err,count;
	int c_fd,c_soc;
	char client_in[DATA_SIZE], client_out[DATA_SIZE];

	if(argc<2)
	{
		printf("give me your ip	!\n");
		exit(0);
	}	
	
	err=pthread_create(&tid, NULL, server_network_func, (void *)argv[1]);
	
	if(err!=0)
	{
		perror("can't create thread!\n");
		exit(0);
	}

	sleep(5);	
	
	c_fd=init_client_network((void *)argv[1]);	
	if(c_fd==-1)
	{
		DEBUG(" listening to telnet failed.\n");
		return -1;
	}
	else
	{
	for(;;)
	{
		if((c_soc = accept(c_fd, NULL, NULL))<0)
		{
			perror("accept client error\n");
			break;
		}


		count = read(c_soc, client_in, DATA_SIZE);
		if(count<0)
		{
			perror("read error\n");
			close(c_soc);
			break;
		}
		err = req_handle(client_in);
		if(err ==-1)
		{
			DEBUG("handle this command error");
			strcpy(client_out, "ERR");
			write(c_soc, client_out, sizeof(client_out));
			close(c_soc);
		}
		else
		{
			strcpy(client_out, "OK");
			write(c_soc, client_out, sizeof(client_out));
			close(c_soc);
		}
		}
	}	
	pthread_join(tid, NULL);
	close(c_fd);
	return 0;
			
}

int req_handle(char * req)
{
	int result1,result2,result3;
	char cmd_in[80], cmd_cancle[80], cmd_type[80];
	
	sscanf(req, "%s", cmd_type);
	cmd_type[strlen(cmd_type)+1]='\0';
	DEBUG("cmd: %s\n", cmd_type);

	if(strcmp(cmd_type, ACQLOCK)==0)
	{
		strcpy(cmd_in, ACQLOCK);	
		strcpy(cmd_cancle, RELLOCK);
	}
	else 
	{
	     if(strcmp(cmd_type, RELLOCK)==0)
	     {
		strcpy(cmd_in, RELLOCK);
	     	strcpy(cmd_cancle," ");
	     }
	     else
	     {
			DEBUG("no such cmd yet\n");
			return -1;	
	     }
	}

	DEBUG("cmd_in: %s, cmd_cancle: %s\n ", cmd_in, cmd_cancle);	
	result1 = send_1_command(Sever_IPS[0], PORT, cmd_in);
	if(result1 == -1)
		return -1;
	else
	{
		result2 = send_1_command(Sever_IPS[1], PORT, cmd_in);
		if(result2 == -1) 
		{
			send_1_command(Sever_IPS[0], PORT, cmd_cancle);
			return -1;
		}
		else 
		{
			result3=send_1_command(Sever_IPS[2],PORT, cmd_in);
			if(result3 == -1)
			{
				send_1_command(Sever_IPS[0], PORT, cmd_cancle);
				send_1_command(Sever_IPS[1], PORT, cmd_cancle);
				return -1;
			}
			return 0;
		}
	}	

}



int send_1_command(char *serv_addr, int port, char* cmd_in)
{
	server_desc_t *serv_desc;	
	comm_data_t *res, *cmd_go;
	int err;
	
	serv_desc = (server_desc_t*) malloc(sizeof(server_desc_t));
	cmd_go = (comm_data_t*) malloc(sizeof(comm_data_t));
	res = (comm_data_t *)malloc(sizeof(comm_data_t));
	
	strcpy(cmd_go->cmd, cmd_in);	

	//send to server
	err=init_server_desc(serv_desc, serv_addr, port);
	
	if(err == -1)
	{
		free(cmd_go);
                free(res);
                free(serv_desc);
		return -1;
	}
	else
	{
		res = issue_server_command(serv_desc, cmd_go, 7);

		DEBUG("res %s\n", res->cmd);
		if (strcmp(res->cmd, "OK")==0)
		{	
			DEBUG("sever %s is ok !\n",serv_addr);
			destroy_server_desc(serv_desc);
			free(cmd_go);
			free(res);
			free(serv_desc);
			return 0;
		}
		else 
		{
			DEBUG("server %s failed!\n", serv_addr);
			destroy_server_desc(serv_desc);
			free(cmd_go);
			free(res);
			free(serv_desc);
			return -1;
		}
	}
	return 0;
}


